<?php

namespace app\check\controller;

use think\Db;
use app\api\controller\v2\Auth;
use app\common\model\User;
use app\common\lib\exception\ApiException;

/**
 * 接口调用验证
 */
class Check extends Auth
{
    const TOKEN = 'zhunleappv_1.1.0';
    public $func = 'CheckAccessTokenSafe';

    protected function _initialize()
    {
        // 校准生辰命令行模式执行，不检查权限
        if (!IS_CLI)
        {
            $this->filter_xss();

            $param = input('param.');
            $headers = request()->header();
            if ((!isset($headers['app-type']) || strpos(config('miniapp.app_types'), $headers['app-type']) === false) && !isset(request()->header()['sign']))
            {
                if (!defined('IS_ACCESS_TOKEN_CHECKED'))
                {
                    if ($this->func == 'CheckAccessTokenSafe')
                    {
                        $accessTokenStatusSafe = $this->CheckAccessTokenSafe();

                        if ($accessTokenStatusSafe['code'] != 200)
                        {
                            echo json_encode($accessTokenStatusSafe);
                            exit;
                        }
                    }
                    if ($this->func == 'check')
                    {
                        $check = $this->check();

                        if ($check['code'] != 200)
                        {
                            echo json_encode($check);
                            exit;
                        }
                    }
                }
                if (isset($param['ucid']))
                {
                    $map = ['uc_id' => $param['ucid']];

                    $this->user = (new User())->getUserinfo($map);
                }
            } else
            {
                parent::_initialize();
            }
        }
    }

    protected function check_func($func = 'CheckAccessTokenSafe')
    {
        $this->func = $func;
    }

    /**
     * @throws \app\common\lib\exception\ApiException
     */
    public function filter_xss()
    {
        $agent = request()->header('user-agent');// sqlmap
        if (
            in_array(request()->ip(), [
                '112.235.60.218',
                '222.177.204.66',
                '112.235.125.107',
                '123.132.58.8',
                '34.228.192.2',
                '112.235.98.34',
                '39.83.165.31',
            ])
            || in_array(htmlspecialchars(input('ucid')), [
                'd27d9cf444c3be10aeac75fa5004742e',
                '9057fe42ac42513b36c9b54008301530',
            ])
            || strpos($agent, 'sqlmap') !== false
            || strpos($agent, 'AppEngine-Google') !== false
            || strpos($agent, 'appid')
        )
            throw new ApiException('404 NOT FOUND', 404);
    }


    public function CheckAccessTokenSafe()
    {
        $access_token = privDecrypt(input('access_token'));

        if (!$access_token)
        {
            return ['code' => 10107, 'msg' => 'Access_token not exist.'];
        }

        $data = Db::table('app_appid')->where("`app_accesstoken`='$access_token'")->find();

        if (empty($data) || $data['app_expire'] + $data['app_gettime'] < time())
        {
            return ['code' => 10108, 'msg' => 'Access_token Expired.'];
        }

        if ($data['app_status'] != 1)
        {
            return ['code' => 10109, 'msg' => 'Premission Dined.'];
        }
        define('IS_ACCESS_TOKEN_CHECKED', true);
        return ['code' => 200, 'msg' => 'ok'];
    }

    public function check()
    {
        //验证身份
        $timeStamp = input('timeStamp');// 时间戳
        $randomStr = input('randomStr');// 随机字符串
        $signature = input('access_token');// 签名
        $str = $this->arithmetic($timeStamp, $randomStr);
        if ($str != $signature)
        {
            return ['code' => 10107, 'msg' => 'Auth failed.'];
        }
        return ['code' => 200, 'msg' => 'ok'];
    }

    /**
     * 签名算法
     * @param $timeStamp int 时间戳
     * @param $randomStr string 随机字符串
     * @return string 返回签名
     */
    protected function arithmetic($timeStamp, $randomStr)
    {
        $arr['timeStamp'] = $timeStamp;
        $arr['randomStr'] = $randomStr;
        $arr['token'] = self::TOKEN;// 口令
        //按照首字母大小写顺序排序
        sort($arr, SORT_STRING);
        //拼接成字符串
        $str = implode($arr);
        //进行加密
        $signature = sha1($str);
        $signature = md5($signature);
        //转换成大写
        $signature = strtoupper($signature);
        return $signature;
    }

    /**
     * 检查档案时间格式
     * @param $year
     * @param $month
     * @param $day
     * @param $hour
     * @param $minute
     * @param $timezone
     * @throws ApiException
     */
    public function checkRecodeData($year = null, $month = null, $day = null, $hour = null, $minute = null, $timezone = null)
    {
        // 年份限制 1900 - 2099
        if ($year === null || $year < 1900 || $year > 2199)
        {
            throw new ApiException('年份无效');
        }
        // 月份限制 1-12
        if ($month === null || $month < 0 || $month > 12)
        {
            throw new ApiException('月份无效');
        }
        // 日期限制 1-31
        if ($day === null || $day < 0 || $day > 31
            || ($this->is_bissextile($year) && $month == 2 && $day > 29)
            || (!$this->is_bissextile($year) && $month == 2 && $day > 28)
            || (in_array($month, [4, 6, 9, 11]) && $day > 30))
        {
            throw new ApiException('日期中天数无效');
//            exit;
        }
        // 小时限制 0-23
        if ($hour === null || $hour < 0 || $hour > 23)
        {
            throw new ApiException('小时无效');
        }
        // 分钟限制 0-59
        if ($minute === null || $minute < 0 || $minute > 59)
        {
            throw new ApiException('分钟无效');
        }
        if ($timezone < -12 || $timezone > 12)
        {
            throw new ApiException('当前时区无效');
        }
    }

    /**
     * 判断是否为闰年
     * 闰年 true || 平年 false
     * @param null $year
     * @return bool
     * @throws ApiException
     */
    private function is_bissextile($year = null)
    {
        if ($year === null)
        {
            throw new ApiException('年份无效');
        }
        if ($year % 400 === 0 || ($year % 100 !== 0 && $year % 4 === 0))
        {
            return true;
        }
        return false;
    }
}
